package com.koudai.finance.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.koudai.finance.dao.ChanceDao;
import com.koudai.finance.dao.StockDao;
import com.koudai.finance.dao.StockWeekDao;
import com.koudai.finance.entity.*;
import com.koudai.finance.service.CommonService;
import com.koudai.finance.service.StockService;
import com.koudai.finance.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: 用户Service
 * @author: ls
 * @Date: 2020-11-10 16:23:11
 */
@Slf4j
@Service
public class StockServiceImpl implements StockService {

    @Resource
    private StockDao stockDao;

    @Resource
    private ChanceDao chanceDao;

    @Resource
    private StockWeekDao stockWeekDao;

    @Resource
    private CommonService commonServiceImpl;

    /**
     * @Description： 获取即将突破的股票
     * @Author: ls
     * @Date: 2021/1/15 4:56 下午
     */
    @Override
    public Map<String, Object> getList() {
        Map<String, Object> resultMap = Maps.newHashMap();
        List<Chance> list = chanceDao.getList();
        if (CollectionUtils.isEmpty(list)) {
            return resultMap;
        }
        String time = DateUtil.getOffsetDayStart(0, DateUtil.DATETIME_FORMAT_DAY);
        // 1、获取今天的数据
        List<Chance> todayList = list.stream().filter(obj -> StringUtils.equals(obj.getBreakDate(), time)).collect(Collectors.toList());
        List<Chance> historyList = list.stream().filter(obj -> !StringUtils.equals(obj.getBreakDate(), time)).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(todayList)) {
            resultMap.put("today", getStockData(todayList));
        }
        // 2、获取历史数据
        if (CollectionUtils.isNotEmpty(historyList)) {
            resultMap.put("history", getStockData(historyList));
        }
        return resultMap;
    }

    /**
     * @Description： 处理数据
     * @Author: ls
     * @Date: 2021/1/15 4:56 下午
     */
    private Map<String, List<String>> getStockData(List<Chance> chanceList) {
        Map<String, List<String>> resultMap = Maps.newHashMap();
        Map<String, List<Chance>> chanceMap = chanceList.stream().collect(Collectors.groupingBy(Chance::getBreakDate));
        chanceMap.forEach((key, value) -> {
            List<String> nameList = value.stream().map(Chance::getName).collect(Collectors.toList());
            resultMap.put(key, nameList);
        });
        return resultMap;
    }


    /**
     * @Description： 计算有机会的股票
     * @Author: ls
     * @Date: 2021/1/15 4:56 下午
     */
    @Override
    public void computeChance() {
        List<Chance> chanceList = Lists.newArrayList();
        List<Stock> list = stockDao.getList();
        List<SysConfig> headerList = commonServiceImpl.getSysConfigList("config");
        Map<String, String> collect = headerList.stream().collect(Collectors.toMap(SysConfig::getName, SysConfig::getValue, (k1, k2) -> k1));
        double bigRate = Double.parseDouble(collect.get("bigRate"));
        double smallRate = Double.parseDouble(collect.get("smallRate"));
        int kCount = Integer.parseInt(collect.get("kCount"));
        String today = DateUtil.getOffsetDayStart(0, DateUtil.DATETIME_FORMAT_DAY);
        for (Stock stock : list) {
            // 1、过滤st股票
            if (StringUtils.contains(stock.getName(), "ST")) {
                continue;
            }
            List<Integer> swList = stockWeekDao.getWeekData(stock.getCode());
            // 2、过滤无k线股票
            if (CollectionUtils.isEmpty(swList)) {
                continue;
            }
            double rate = collect.containsKey(stock.getCode()) ? smallRate : bigRate;
            Integer currentClose = swList.get(0);
            // 3、过滤出可能突破横盘震荡区间的股票，且历史收盘价振幅不超过配置比例
            boolean flag4 = checkBreak(currentClose, rate, kCount, swList);
            if (flag4) {
                Chance sc = Chance.builder().build();
                BeanUtils.copyProperties(stock, sc);
                sc.setBreakDate(today);
                chanceList.add(sc);
            }
        }
        if (CollectionUtils.isEmpty(chanceList)) {
            return;
        }
        chanceDao.batchSave(chanceList);
    }

    /**
     * @Description： 过滤出突破的股票，且历史收盘价振幅不超过配置比例
     * @Author: ls
     * @Date: 2021/1/15 4:56 下午
     */
    private boolean checkBreak(Integer currentClose, double rate, int kCount, List<Integer> swList) {
        // 1、历史k线数量低于配置数量进行过滤
        if (swList.size() < kCount) {
            return false;
        }
        // 2、历史最高收盘价与最低收盘价不能高于一定比例
        List<Integer> subList = swList.subList(0, kCount);
        Integer min = subList.stream().min(Comparator.naturalOrder()).orElse(0);
        Integer max = subList.stream().max(Comparator.naturalOrder()).orElse(0);
        if (max > (min * rate)) {
            return false;
        }
        // 3、当前收盘价要比以往所有k线收盘价都高
        for (int i = 1; i < subList.size(); i++) {
            Integer beforeClose = subList.get(i);
            if (currentClose < beforeClose) {
                return false;
            }
        }
        return true;
    }

    /**
     * @Description： 同步周线历史数据
     * @Author: ls
     * @Date: 2021/1/15 4:56 下午
     */
    @Override
    public void syncWeekData() {
        // 1、先清空所有周k线数据
        stockWeekDao.del();
        // 2、获取历史周k线
        List<Stock> stockList = stockDao.getList();
        for (Stock stock : stockList) {
            // 1、过滤st股票
            if (StringUtils.contains(stock.getName(), "ST")) {
                continue;
            }
            Integer record = stockWeekDao.checkIsExist(stock.getCode());
            if (record != null) {
                continue;
            }
            JSONObject jsonObject = StockUtil.getWeekData(stock.getExchange(), stock.getCode(), "json");
            JSONArray dataArr = jsonObject.getJSONArray("data");
            if (CollectionUtils.isEmpty(dataArr)) {
                continue;
            }
            List<StockWeek> swList = Lists.newArrayList();
            for (Object obj : dataArr) {
                JSONObject json = (JSONObject) obj;
                String code = json.getString("ticker");
                Integer open = new BigDecimal(json.getString("open")).multiply(BigDecimal.valueOf(100)).intValue();
                Integer high = new BigDecimal(json.getString("high")).multiply(BigDecimal.valueOf(100)).intValue();
                Integer low = new BigDecimal(json.getString("low")).multiply(BigDecimal.valueOf(100)).intValue();
                Integer close = new BigDecimal(json.getString("close")).multiply(BigDecimal.valueOf(100)).intValue();
                Integer volume = json.getInteger("volume");
                String date = json.getString("date");
                StockWeek sw = StockWeek.builder().code(code).open(open).high(high).low(low).close(close).volume(volume).closeDate(date).build();
                swList.add(sw);
            }
            stockWeekDao.batchSave(swList);
        }

    }

    /**
     * @Description：同步股票代码
     * @Author: ls
     * @Date: 2021/1/15 4:56 下午
     */
    @Override
    public void syncCode() {
        // 1、先清空所有股票数据
        stockDao.del();
        //2、重新获取股票信息
        List<String> exchangeList = Lists.newArrayList("XSHG", "XSHE");
        for (String exchange : exchangeList) {
            JSONObject jsonObject = StockUtil.getStockList(exchange, null, "1", "json");
            JSONArray dataArr = jsonObject.getJSONArray("data");
            if (CollectionUtils.isEmpty(dataArr)) {
                continue;
            }
            // 3、拆成50个一组，批量保存
            List<List<Object>> lists = Lists.partition(dataArr, 50);
            for (List<Object> innerList : lists) {
                List<Stock> stockList = Lists.newArrayList();
                for (Object obj : innerList) {
                    JSONObject json = (JSONObject) obj;
                    Stock stock = Stock.builder().exchange(exchange).code(json.getString("ticker")).name(json.getString("name")).build();
                    stockList.add(stock);
                }
                stockDao.batchSave(stockList);
            }
        }
    }

}